﻿using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebTest.Core.Entities;
using WebTest.Core.Entities.OrderAggregate;
using WebTest.Infrastructure.Interfaces;

namespace WebTest.Infrastructure.Data
{
    public static class OrderContextSeed
    {
        public static async Task<IHost> SeedOrderContextAsync(this IHost host, IServiceProvider provider)
        {
            using (var context = provider.GetRequiredService<OrderContext>())
            {
                await context.Database.MigrateAsync();

                await SeedMemberAndRoleAsync(context);

                await SeedOrderAndOrderItem(context);
            }

            //await SeedOrderAndOrderItem(provider.GetRequiredService<IDataAccess>());

            return host;
        }

        private static async Task SeedMemberAndRoleAsync(OrderContext context)
        {
            Role role = new Role("Admin");

            Member member = new Member("api", "Api Account");
            member.SetPassword("api@password");

            if (!context.Set<Role>().Any())
            {
                await context.AddAsync(role);
                await context.SaveChangesAsync();
            }

            if (!context.Set<Member>().Any())
            {
                await context.AddAsync(member);
                role.AddMember(member);

                await context.SaveChangesAsync();
            }
        }

        static string random => Guid.NewGuid().ToString();
        static decimal price => (decimal)(new Random().NextDouble() + new Random().Next());

        //private static async Task SeedOrderAndOrderItem(IDataAccess dataAccess)
        //{
            
        //}
        private static async Task SeedOrderAndOrderItem(OrderContext context)
        {
            if (context.Set<Order>().Any()) return;

            var member = await context.Set<Member>().FirstAsync();

            var address = new Address("alias", "detal");

            await context.Set<Address>().AddAsync(address);

            await context.SaveChangesAsync();

            Stopwatch stopwatch1 = new Stopwatch();

            stopwatch1.Start();

            //int start = 0, end = 999999;

            //Parallel.For(start, end, new ParallelOptions { MaxDegreeOfParallelism = 100 }, (index) =>
            //  {
            //      for(int x = 0; x < 1000; x++)
            //      {
            //          var order = new Order();
            //          order.SetMember(member);
            //          order.SetOrderAddress(address);
            //          order.AddOrderItem(new OrderItem($"order{random}", 1.23m + x % 5, x % 5));

            //          context.Add(order);
            //      }
            //      context.SaveChanges();
            //  });

            for (var x = 0; x < 1000; x++)
            {
                Stopwatch stopwatch2 = new Stopwatch();
                stopwatch2.Start();

                for (var j = 0; j < 1000; j++)
                {
                    var order = new Order();
                    order.SetMember(member);
                    order.SetOrderAddress(address);
                    order.AddOrderItem(new OrderItem($"order{random}", 1.23m + j % 5, j % 5));

                    await context.AddAsync(order);
                }
                await context.SaveChangesAsync();

                stopwatch2.Stop();
                Console.WriteLine($"{(x + 1) * 1000} insert:{stopwatch2.ElapsedMilliseconds} ms");
            }

            stopwatch1.Stop();

            Console.WriteLine($"Total:{stopwatch1.ElapsedMilliseconds} ms");
        }
    }
}
